#ifndef VNODE_H_
#define VNODE_H_

#include <string>
#include <vector>
#include <map>

class VNode;


void unlink_vnode(VNode *vnode);


class VNode {
public:
	enum class Type { unknown, dir, file };

protected:
	std::string m_name;
	Type m_type;
	VNode *m_parent;
	int m_nlinks;

public:
	VNode();
#ifndef _MSC_VER
	virtual ~VNode() = default;
#else
	virtual ~VNode() {}
#endif

	virtual void set_name(const char *name);
	virtual const char *get_name() const;

	virtual Type get_type() const;
	virtual bool is_dir() const;
	virtual bool is_file() const;
	virtual bool is_mountpoint() const;
	virtual bool is_real() const;		// true if it's a real file/dir on disk

	virtual VNode *get_parent();
	virtual const VNode *get_parent() const;

	friend class VNodeDir;
	friend class VNodeFile;
	friend void unlink_vnode(VNode *vnode);
};


class VNodeDir : public VNode {
private:
	std::vector<VNode*> m_child;
	std::map<std::string, int> m_child_idx;
	VNodeDir *m_dirlink;	// if this link is not-null ignore the children

	// find a path starting from this directory, path must be relative
	virtual VNode *lookup(char *path);

public:
	VNodeDir();
	virtual ~VNodeDir();

	virtual VNodeDir *get_dirlink() const;
	virtual bool is_mountpoint() const;

	virtual bool add_child(VNode *node);				// O(logn)

	// returns the index of the child being removed or -1
	virtual int remove_child(int idx);					// O(logn)
	virtual int remove_child(const char *name);			// O(logn)

	virtual VNode *get_child(int idx);					// O(1)
	virtual const VNode *get_child(int idx) const;		// O(1)

	virtual VNode *get_child(const char *name);				// O(logn)
	virtual const VNode *get_child(const char *name) const;	// O(logn)

	// returns the index of the child or -1 if not found
	virtual int get_child_index(const char *name) const;	// O(logn)

	// mount something, e.g. a directory, or an archive to this node.
	virtual bool mount(const char *path);
	virtual bool mount(VNodeDir *vdir);
	virtual bool umount();

	friend VNode *lookup_path(const char *path);
};

class VNodeFile : public VNode {
public:
	VNodeFile();
};


#endif	// VNODE_H_
